package com.humingzhang.client.fastdfs;

import com.humingzhang.client.FileClient;
import org.apache.commons.io.IOUtils;
import org.csource.common.MyException;
import org.csource.fastdfs.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Properties;

/**
 * FastDFS SDK
 *
 * @author minghu.zhang
 */
public class FastDfsFileClient implements FileClient {

    /**
     * tracker server
     */
    private final TrackerServer trackerServer;
    /**
     * storage server
     */
    private final StorageServer storageServer;
    /**
     * group name
     */
    private final String groupName;

    public FastDfsFileClient(FastDfsConfig fastDfsConfig) {
        try {
            // 初始化FastDfs客户端
            Properties properties = buildInitProperties(fastDfsConfig.getTrackerIpList(),
                    fastDfsConfig.getTrackerHttpPort(), fastDfsConfig.getFastDfsSecretKey());
            ClientGlobal.initByProperties(properties);
            TrackerClient trackerClient = new TrackerClient();
            trackerServer = trackerClient.getConnection();
            storageServer = trackerClient.getStoreStorage(trackerServer);
        } catch (IOException | MyException e) {
            throw new RuntimeException("FastDFS Client初始化失败", e);
        }
        this.groupName = fastDfsConfig.getGroupName();
    }

    /**
     * 构建配置属性
     */
    private Properties buildInitProperties(List<String> trackerIpList, String trackerHttpPort, String fastDfsSecretKey) {
        Properties properties = new Properties();

        StringBuilder serverGroup = new StringBuilder();
        for (String ip : trackerIpList) {
            serverGroup.append(",").append(ip);
        }

        if (trackerIpList.isEmpty()) {
            throw new IllegalArgumentException("FastDfs Tracker列表不能为空");
        }

        properties.setProperty("fastdfs.tracker_servers", serverGroup.substring(1));
        properties.setProperty("fastdfs.http_tracker_http_port", trackerHttpPort == null ? "80" : trackerHttpPort);
        properties.setProperty("fastdfs.http_secret_key", fastDfsSecretKey == null ? "" : fastDfsSecretKey);

        return properties;
    }

    /***
     * 上传文件
     */
    @Override
    public String upload(String path, InputStream input) {
        try {
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);

            String extension = path.substring(path.lastIndexOf("."));

            ByteArrayOutputStream output = new ByteArrayOutputStream();
            IOUtils.copy(input, output);

            String[] uploadResult = storageClient.upload_file(groupName, output.toByteArray(), extension, null);

            return uploadResult[1];
        } catch (Exception e) {
            throw new RuntimeException("文件存储异常," + e.getMessage(), e);
        }
    }

    /***
     * 文件下载
     */
    @Override
    public void download(String path, OutputStream output) throws IOException {
        try {
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);

            FileInfo fileInfo = storageClient.query_file_info(groupName, path);

            // 检查文件是否存在
            if (fileInfo == null) {
                throw new RuntimeException("文件不存在");
            }

            byte[] original = storageClient.download_file(groupName, path);
            IOUtils.write(original, output);
        } catch (MyException e) {
            throw new RuntimeException("文件下载失败," + e.getMessage(), e);
        }
    }

    /***
     * 文件删除
     */
    @Override
    public void delete(String path) throws IOException {
        StorageClient storageClient = new StorageClient(trackerServer, storageServer);
        try {
            storageClient.delete_file(groupName, path);
        } catch (MyException e) {
            throw new RuntimeException("文件删除失败," + e.getMessage(), e);
        }
    }

    @Override
    public void close() {
        try {
            trackerServer.close();
            storageServer.close();
        } catch (IOException ignore) {
        }
    }
}
